home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DDJMAG / DDJ9110.ZIP / OODEBUGR.ASC < prev    next >
Text File  |  1991-09-10  |  8KB  |  244 lines

  1. _A MINIMAL OBJECT-ORIENTED DEBUGGER FOR C++_
  2. by William M. Miller
  3.  
  4. [LISTING ONE]
  5.  
  6. // MOOD.hxx by William M. Miller, 8/3/91. MOOD user declarations.
  7.  
  8. /* This header file is included in every module which is to be metered
  9.  * by MOOD.  Its actions are controlled by the preprocessor variable
  10.  * DEBUGGER_ON. If not this is not defined, no debugger actions will occur.
  11.  */
  12. #ifndef _DEBUGGER_DEFS
  13. #define _DEBUGGER_DEFS
  14.                       // Conditions under which cond_break may be called:
  15. enum break_condition { 
  16.    PROG_START,  PROG_END,  FCN_ENTRY,  FCN_EXIT,  OBJ_CTOR,  OBJ_DTOR,
  17.    USER_BP
  18.    };
  19.  
  20. /* The cond_break() function is called in all the above contexts for two
  21.  * purposes: 1) to display trace information when verbose mode is on, and
  22.  * 2) to break under the appropriate conditions to allow the user to
  23.  * interact with the debugger.  The default arguments are to allow a user
  24.  * program to contain the call "cond_break();" with no arguments to perform
  25.  * an unconditional breakpoint into the debugger's interactive mode.
  26.  */
  27. void cond_break(break_condition cond = USER_BP, const char* name = 0,
  28.       void* addr = 0);
  29.  
  30. /* The trace class is intended to allow function tracing.  Each function or
  31.  * block which should be included in the trace should declare an object of
  32.  * class trace at the very beginning.  The result, in verbose mode, will be
  33.  * to display the function/block name at entry and exit; this name can also
  34.  * be used to set a breakpoint from the debugger's interactive mode.
  35.  */
  36. class trace {
  37. public:
  38. #ifdef DEBUGGER_ON
  39.     trace( const char* fcn_name): _name(fcn_name) 
  40.                   {  cond_break( FCN_ENTRY, _name);  }
  41.    ~trace( )      {  cond_break( FCN_EXIT,  _name);  }
  42. private:
  43.    const char* _name;
  44. #else
  45.    trace( const char* ) { }
  46. #endif
  47.    };
  48.  
  49. /* The monitored class is intended for use as a virtual base class of any
  50.  * classes whose construction/destruction is to be traced in verbose mode
  51.  * or whose values are to be displayed interactively.  Derived classes must
  52.  * pass the object or class name to the constructor and must supply an
  53.  * override to the display() member function.
  54.  */
  55. class monitored {
  56. public:
  57. #ifdef DEBUGGER_ON
  58.     monitored( const char* obj_name ): _name(obj_name) 
  59.                      {  cond_break(OBJ_CTOR, _name, this);   };
  60.    ~monitored( )     {  cond_break(OBJ_DTOR, _name, this);   }
  61.    virtual void display() = 0;
  62. private:
  63.    monitored() { }  // keep cfront 2.0 happy -- it requires a default
  64.                     // constructor in virtual base classes for no good reason.
  65.    const char* _name;
  66. #else
  67.    monitored( const char* ) { }
  68.    monitored( ) { }
  69. #endif
  70.    };
  71.  
  72. /* The following class and static object call cond_break exactly once at
  73.  * program start, before any debuggable object is created, to allow the
  74.  * user to set up tracing and breakpoints, and once at the end of execution
  75.  * to allow for any needed cleanup.
  76.  */
  77. #ifdef DEBUGGER_ON
  78. class init_ctl {
  79. public:
  80.     init_ctl( )   { if (_count++ == 0)   cond_break(PROG_START);   }
  81.    ~init_ctl( )   { if (--_count == 0)   cond_break(PROG_END);     }
  82. private:
  83.    static int _count;
  84. };
  85.  
  86. static init_ctl dbg_init;
  87. #endif
  88. #endif
  89.  
  90.  
  91. [LISTING TWO]
  92.  
  93. // tdbg.cxx by William M. Miller, 8/3/91. This is a sample
  94. // program to be debugged with MOOD. A transcript of the debugging
  95. // session is shown in Example 3, accompanying this article.
  96.  
  97. extern "C" {
  98. #include <stdio.h>
  99. }
  100. #include "MOOD.hxx"
  101.  
  102. struct foo: virtual monitored {
  103.    foo( const char* nm ): monitored(nm), my_name(nm) { }
  104.    void display( )        { fprintf(stderr, "%s\n", my_name);  }
  105.    const char* my_name;
  106.    };
  107. void x();
  108. void y();
  109. void z();
  110.  
  111. int main() {
  112.    trace tt("main");
  113.    foo* p = new foo("*p");
  114.    x();
  115.    z();
  116.    delete p;
  117.    return 0;
  118.    }
  119.  
  120. void x() {
  121.    trace tt("x");
  122.    foo xf("xf");
  123.    y();
  124.    }
  125.  
  126. void y() {
  127.    trace tt("y");
  128.    foo yf("yf");
  129.    }
  130.  
  131. void z() {
  132.    trace tt("z");
  133.    foo zf("zf");
  134.    }
  135.  
  136.  
  137. [LISTING THREE]
  138.  
  139. // MOOD.cxx, by William M. Miller, 8/3/91. MOOD kernel definitions.
  140.  
  141. /* This routine implements the user interface of MOOD, the Minimal Object
  142.  * Oriented Debugger. Example 2 in the accompanying article describes
  143.  * currently available commands: s, g, d, v, and q.
  144.  */
  145. extern "C" {
  146. #include <stdio.h>
  147. #include <string.h>
  148. }
  149. #define DEBUGGER_ON 1
  150. #include "MOOD.hxx"
  151.  
  152. /* The objp() function does a system-dependent conversion of an ASCII pointer
  153.  * specification into a pointer to a monitored object.
  154.  */
  155. monitored* objp(const char* str);
  156.  
  157. /* The cond_break() function is called under the various circumstances
  158.  * described by the enumeration break_condition.  It prints a message, if
  159.  * required, describing the reason for its call, and optionally enters
  160.  * interactive mode to take commands.
  161.  */
  162. void cond_break(break_condition cond, const char* name, void* addr) {
  163.  
  164.    static int tracing = 0;          // => verbose mode
  165.    static char brk_name[128] = "";  // name on which to break
  166.    static int was_step = 1;         // last cmd was "step" => go to
  167.                                     // interactive mode
  168.    char buff[128];                  // command line buffer
  169.  
  170. /* We enter the display and possible interactive mode code under the following
  171.  * conditions:
  172.  * 1) We are tracing (verbose mode).
  173.  * 2) We are stepping.  (Note: this is initially TRUE, which takes care of
  174.  *    getting into interactive mode on the PROG_START call.)
  175.  * 3) The breakpoint name was set and the current name matches it, or this
  176.  *    is a user breakpoint call with no name
  177.  * 4) The breakpoint name was not set and this is a user breakpoint call.
  178.  */
  179.    if (tracing || was_step ||
  180.          (brk_name[0] && ((strcmp(brk_name, name) == 0) ||
  181.          (cond == USER_BP && !name))) || (!brk_name[0] && cond == USER_BP)) {
  182.  
  183.       switch(cond) {     // Print an appropriate message:
  184.  
  185.       case PROG_START:
  186.          fprintf(stderr,"MOOD: Minimal Object Oriented Debugger, V. 0.0\n");
  187.                                                                        break;
  188.       case PROG_END:    fprintf(stderr, "End of execution.\n");        break;
  189.  
  190.       case FCN_ENTRY:   fprintf(stderr, "Enter %s\n", name);           break;
  191.  
  192.       case FCN_EXIT:    fprintf(stderr, "Exit  %s\n", name);           break;
  193.  
  194.       case OBJ_CTOR:    fprintf(stderr, "Construct %s @ %p\n", name, addr);
  195.                                              break;
  196.       case OBJ_DTOR:    fprintf(stderr, "Destruct  %s @ %p\n", name, addr);
  197.                                                                        break;
  198.       case USER_BP:     fprintf(stderr, "Breakpoint %s (%p)\n", name, addr);
  199.                                                                        break;
  200.       }  // switch
  201.  
  202. /* We enter interactive mode if any of the above conditions other than
  203.  * tracing is met.  (This implies that named user breakpoints are skipped
  204.  * if the user uses a g <name> command in which the name does not match
  205.  * the breakpoint name, but that unnamed user breakpoints are always
  206.  * effective, as are named user breakpoints after a g command with no name.)
  207.  */
  208.       if (was_step || (brk_name[0] && ((strcmp(brk_name, name) == 0) ||
  209.             (cond == USER_BP && !name))) ||
  210.             (!brk_name[0] && cond == USER_BP)) {
  211.  
  212. // Reset breakpoint conditions
  213.          was_step = 0;
  214.          brk_name[0] = 0;
  215.  
  216. // Main command loop
  217.          do {
  218.             fprintf(stderr, "cmd> ");
  219.             gets(buff);
  220.             switch(buff[0]) {
  221.  
  222.             case 'd':  objp(buff + 2)->display();                  break;
  223.             case 'g':  if (buff[1])  strcpy(brk_name, buff + 2);   break;
  224.             case 'q':  tracing = 0;                                break;
  225.             case 's':  was_step = 1;                               break;
  226.             case 'v':  tracing = 1;                                break;
  227.             }     // switch
  228.  
  229.          } while(buff[0] != 's' && buff[0] != 'g');
  230.       }     // if (interactive)
  231.    }     // if (message)
  232. }     // cond_break()
  233.  
  234. monitored* objp(const char* str) {
  235.         monitored* p;
  236.         sscanf(str, "%p", &p);
  237.         return p;
  238.         }
  239.  
  240. int init_ctl::_count;
  241.  
  242.  
  243.  
  244.